﻿using System;
using System.Linq;
using System.Reflection;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Luna.NHibernate;
using XWord.Fundamental.Domain;
using Microsoft.Practices.Composite.Modularity;


namespace XWord.GuyWire.Configurators
{
    public class RepositoriesConfigurator : IConfigurator
    {
        #region IConfigurator Members

        public void Configure(IWindsorContainer container)
        {
            var moduleCatalog = container.Resolve<IModuleCatalog>();
            foreach (var module in moduleCatalog.Modules)
            {
                var repositoryServices = Assembly.Load(new AssemblyName(string.Format("{0}.Data", module.ModuleName))).GetTypes()
                    .Where(t => t.IsInterface);
                var repositoryImpl = Assembly.Load(new AssemblyName(string.Format("{0}.Data", module.ModuleName))).GetTypes()
                    .Where(t => t.GetInterfaces().Any(i => repositoryServices.Contains(i)));

                foreach (Type service in repositoryServices)
                    foreach (Type impl in repositoryImpl)
                        if (service.IsAssignableFrom(impl))
                            container.Register(Component.For(service).ImplementedBy(impl).LifeStyle.Transient);

                var nhEntities = Assembly.Load(new AssemblyName(string.Format("{0}.Domain", module.ModuleName))).GetTypes()
                    .Where(t => t.IsClass && BaseTypeIsEntity(t.BaseType));

                foreach (var type in nhEntities)
                    RegisterGenericRepository(container, type);
            }
        }

        #endregion

        private static bool BaseTypeIsEntity(Type baseType)
        {
            while (baseType != null)
            {
                if (baseType == typeof(Entity)) return true;
                baseType = baseType.BaseType;
            }
            return false;
        }

        private static void RegisterGenericRepository(IWindsorContainer container, Type type)
        {
            var typeArgs = new[] { type };
            var service = typeof(IRepository<>).MakeGenericType(typeArgs);
            var impl = typeof(Repository<>).MakeGenericType(typeArgs);
            container.Register(Component.For(service).ImplementedBy(impl).LifeStyle.Transient);
        }
    }
}